\chapter{Изображения}
\pagenumbering{arabic}

\section{Чтение MAT-файлов MATLAB в nip2}
Теперь замечательный графический анализатор nip2 полностью поддерживает чтение MAT-файлов, в которых MATLAB записывает данные рабочего окружения с двойной точностью (double precision). 


\subsection{Для чего нужно открывать MAT-файлы в nip2}
Упреждая возможные вопросы "а зачем нам проприетарный mat когда есть csv" отвечу: запись в открытый формат CSV в матлабе происходит несколько нетривиальным образом и можно записать только одну переменную. 


\subsection{Просмотр MAT-файлов MATLAB в nip2}
Здесь всё довольно просто: в диалоге открытия явно указываем, что хотим просмотреть MATLAB's mat-files и далее открываем такой файл. Пример на скриншоте - легендарная Лена.


А теперь примерчик посложнее - загружаем изображение усреднённых темновых шумов цифровой камеры и берём от них Фурье-преобразование (на том же скриншоте открыта в левом нижнем углу неудачная фотография от скоростной съёмки):


Так что наши данные теперь можно просмотреть без томительного ожидания, пока MATLAB откроет эти файлы. Кстати о данных в форматах CSV и MAT...


\subsection{Данные в CSV и MAT-форматах: особенности записи MATLAB и просмотр nip2}
Эту заметку я хотел сделать отдельным постом, но решил выложить здесь же. Появился тут вопрос: как сохраняет MATLAB данные с плавающей точкой в разных форматах. Для этого мы провели маленькое расследование...


\subsection{Подготовка}
Ответ состоит из нескольких частей. Да, Матлаб может сохранять данные в своём формате mat, и его может прочесть та же Octave (теперь и nip2 с использованием библиотеки matio). Для проверки сгенерируем матрицу

\lstset{language=Matlab}
\begin{lstlisting}
>> a = magic(5)

a =

17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9

>> b =a./3

b =

5.6667 8.0000 0.3333 2.6667 5.0000
7.6667 1.6667 2.3333 4.6667 5.3333
1.3333 2.0000 4.3333 6.6667 7.3333
3.3333 4.0000 6.3333 7.0000 1.0000
3.6667 6.0000 8.3333 0.6667 3.0000

>> b(2,2)=1.09878432753084573248523475
>> b(2,3)=2^20
\end{lstlisting}


Видим только первые четыре числа после запятой - это потому, что по умолчанию MATLAB отображает числа в коротком формате. Изменить этот формат можно командой format type.

Чтобы сделать задачу более наглядной, в матрицу записали два числа: одно с разными числами после запятой, а второе - очень большое \verb+(2^20)+. Теперь сохраняем в MAT-файл и CSV командами:

\begin{lstlisting}
save('magic5x5doubleafterformatlong.mat', 'b'); %% ЭтоСохраняется MATфайл
csvwrite('magic5x5double-afterformatlong.csv',b); %% ЭтоСохраняется CSVфайл
\end{lstlisting}


Теперь открываем их и сравниваем с исходниками...

\subsection{Данные в MAT-файле.}
В MAT-файлах всё чисто: он сохраняет так же, как и открывает.

\begin{lstlisting}
>> load('magic5x5doubleafterformatlong.mat')
>> b
b =
1.0e+06 *
Columns 1 through 4
0.00000566666667 0.00000800000000 0.00000033333333 0.00000266666667
0.00000766666667 0.00000109878433 1.04857600000000 0.00000466666667
0.00000133333333 0.00000200000000 0.00000433333333 0.00000666666667
0.00000333333333 0.00000400000000 0.00000633333333 0.00000700000000
0.00000366666667 0.00000600000000 0.00000833333333 0.00000066666667
Column 5
0.00000500000000
0.00000533333333
0.00000733333333
0.00000100000000
0.00000300000000
>> b(2,2)
ans =
1.09878432753085
>> b(2,3)
ans =
1048576
\end{lstlisting}



\subsection{Данные в CSV-файле.}
А вот тут начинаются приключения. MATLAB записывает в CSV формат данные с точностью, такой же, как при отображении. То есть, например, при отображении используется вывод только первых 4 чисел после запятой - следовательно, сохранены они в CSV будут так же.

\begin{lstlisting}
>> b(2,2)

ans =

1.0988
\end{lstlisting}


С большими числами тоже самое: они сохраняются в экспоненциальной форме с точностью, установленной для отображения (по умолчанию 4 знака). Это так же видно в CSV-файле (записывает с той точностью, с которой отображает). У одной и той же матрицы, сохранённой в CSV и MAT сходный размер.


\begin{lstlisting}
>> b(2,3)=2^20

b =

1.0e+06 *

0.0000 0.0000 0.0000 0.0000 0.0000
0.0000 0.0000 1.0486 0.0000 0.0000
0.0000 0.0000 0.0000 0.0000 0.0000
0.0000 0.0000 0.0000 0.0000 0.0000
0.0000 0.0000 0.0000 0.0000 0.0000

>> b(2,3)

ans =

1048600

>> 2^20

ans =

1048576
\end{lstlisting}


Именно так оно и происходит по умолчанию: MATLAB просто округляет числа при записи в CSV до четырёх значащих чисел. Для того, чтобы запись происходила с нужной нам точностью в CSV, следует использовать команду dlmwrite и явно указывать точность. Например так:

\begin{lstlisting}
>> dlmwrite('magic5x5double1-dlmwrite-precision12f.csv', b, 'precision', '%12.12f')
\end{lstlisting}


Это записывает матрицу в CSV формат с переменной b и обеспечивает точность 12 значащих чисел. Так что стоит аккуратнее обходиться с командами записи: csvwrite вам запишет, конечно, переменную, но с малой точностью. Это может стать источником трудноуловимых проблем.


\subsection{Отображение данных в MAT и CSV форматах в nip2}
Теперь, возвращаясь к теме поста, в последних версиях (nip2 и vips > 7.18.2) замечательного графического анализатора nip2 можно просматривать не только данные в CSV, но и в MAT-файлах. Это очень и очень удобная возможность: например, усреднённое изображение в MAT-файле можно проанализировать и посмотреть без необходимости загружать лишний раз MATLAB. Особенно это актуально, если изображение в MAT-файле больших размеров. Точность просмотра CSV и MAT-данных составляет 5 значащих цифр.







\section{Установка и впечатления новой версии графического анализатора NIP2}
Не так давно вышла новая версия библиотеки обработки изображений VIPS, а вместе с ней и графическая оболочка nip2. Несколько слов о том, что изменилось и как новую версию быстро собрать и использовать.

\subsection{Фильтры}
В составе Nip2 теперь улучшенные фильтры морфологического анализа (пока только бинарная морфология), многие фильтры получили возможность точной настройки (custom kernels), а так же включён шумоподавляющий фильтр GREYstoration, основанный на анизотропной диффузии. GREYstoration интересен тем, что реализует подавление шума при помощи весьма изощрённого "сглаживания" изображения. В результате это важные детали не размываются, а шума становится намного меньше. Техника anisotropic diffusion известна довольно давно, однако реализация в Nip2 достаточно быстрая и нетребовательная к памяти, что важно при работе с большими изображениями.

\subsection{Именование рядов}
Это полезная функция, если требуется анализировать много изображений. Тогда можно задать один workspace и просто заменять одно изображение - остальное пересчитается автоматически. Именованные ряды позволяют проще отличать конечные результаты анализа от промежуточных подсчётов.
Просто впишите в пустую клетку:

\begin{lstlisting}
Mean=Math_stats_item.Mean_item.action A1
\end{lstlisting}
\lstset{language=}


и вы получите именованную ячейку, содержимое которой есть среднее значение изображения в ячейке А1. Именовать по-русски пока нельзя, только на английском.


\subsection{Горячие клавиши на элементы меню}
Очень и очень полезная возможность! Открываем меню, доходим до нужной нам функции, подсвечиваем её и наживаем к примеру CTRL+M - и теперь на функцию повешена горячая кнопка. Теперь, чтобы посчитать среднее значение на изображении, просто выделяем изображение и нажимаем CTRL+M.




\section{Продвинутые средства анализа изображений в nip2}
Некоторое время назад я уже писал об этом замечательном графическом редакторе nip2 для огромных изображений - сейчас я хочу записать методы обработки изображений в нём. По роду текущей деятельности приходится иметь дело с 12-битными изображениями (конвертированные RAW-файлы при помощи dcraw в полностью документальный режим), так что просматривать и работать с такими картинками в обычных редакторах (типа GiMP или Krita) не удобно. Зато в nip2 можно и просматривать изображения любой битности, и выполнять весьма изощрённые методы обработки. Об этом ниже и будет говориться.

\subsection{Изменение масштаба яркости при просмотре}
Для того, чтобы изменить масштаб значений для отображения, следует дважды щёлкнуть по миниатюре и перетащить ползунки масштаба для лучшего масштабирования. Это не изменяет само изображение, а лишь масштабирует его для просмотра. Закрываем окно, в котором меняли масштаб просмотра, что сохраняет настройки для текущего рабочего окружения.


\subsubsection{Быстрое масштабирование}
Для того, чтобы изменить масштаб, совсем не обязательно искать на панели инструментов какую-то кнопку: достаточно, удерживая клавишу CTRL на клавиатуре, покрутить колёсиком мыши - и изображение в окне будет менять свой масштаб. Естественно, на оригинальном файле это не отразится.


\subsubsection{Быстрое выделение области}
Если нужно быстро выделить область интереса на изображении, достаточно зажать клавишу CTRL на клавиатуре и начать выделять мышью нужную область. Тут же будет создана новая область с названием, соответствующем текущему ряду и последнему свободному номеру ячейки (например, если ряд B и ячейка 14 последняя - новая будет называться B15).


\subsubsection{Быстрое перемещение по изображению}
Колёса продолжают рулить! Колесом мыши можно скроллить изображение вверх-вниз, а если зажать SHIFT и использовать колесо мыши - скроллинг будет в направлениях "влево-вправо". Очень удобно перемещаться так без использования полос прокрутки.


\subsubsection{Горячие клавиши в nip2}
Если вы часто используете какую-то функцию, есть смысл поставить на неё горячую клавишу. Для этого открываем меню, доходим до нужной нам функции кнопками клавиатуры, подсвечиваем её (или нажимаем её кнопкой мыши и держим для подсветки) и наживаем к примеру сочетание клавиш CTRL+M - и теперь эту функцию можно вызвать по нажатию CTRL+M.



\subsection{Анализ изображений в nip2}
С помощью nip2 можно проводить довольно сложный анализ изображений: Фурье-анализ, корреляционный анализ, свёртка, low-pass/high-pass фильтры и прочее.

\subsubsection{Фурье-анализ в nip2}
Часто бывает необходимо видеть Фурье-спектр изображения, особенно тогда, когда к нему применяются методы обработки. Для этого идём в Toolkits - Math - Fourier - Forward для прямого фурье-преобразования. Считается оно в первый раз довольно долго, зато потом будет пересчитываться быстро.

Там же, в nip2, можно выполнить и обратное фурье-преобразование. Для этого идём в Toolkits - Math - Fourier - Reverse и получаем назад своё изображение.

\subsubsection{Гистограмма изображения в nip2}
Гистограмма это зависимость количества пикселей одного уровня яркости от яркости изображения - она даёт представление о том, пикселей какой яркости на изображении больше или меньше. Функция чрезвычайно полезная при анализе изображений, и, разумеется, она присутствует в nip2. Для этого выделяем изображение, которое собираемся анализировать, и идём в меню Toolkits - Histogram - Find - One Dimension.
В результате, как на скриншоте выше, имеем красивую и информативную гистограмму изображения.



\subsection{Изменение изображений в nip2}
Некоторые привычные операции, такие как кадрирование, в nip2 есть, просто они могут выглядеть, согласно философии nip2, несколько непривычно...

\subsubsection{Кадрирование}
Есть и эта операция, причём её можно делать и визуально, и имея точные координаты.
Точное кадрирование можно осуществить, либо когда вам известны координаты области, либо используя nip2 в поточном режиме (для этого следует использовать команду vips и мануал к ней). Отмечаем ячейку с изображением, которое необходимо кадрировать, и идём в Toolkits - Image - Crop. После этого появится ещё одна ячейка ниже, и
потребуется указать координаты среза.

Визуальное кадрирование можно применить к изображению, открыв изображение на просмотр в окне, идём в меню File - New - New Region. Теперь меняем размер области и её положение по вкусу.
А можно сделать и ещё проще: для кадрирования в nip2 достаточно, зажав клавишу CTRL, выделить желаемую область на изображении - и в следующей ячейке сразу же появится желаемая область выделения.


\subsubsection{Порог}
Казалось бы, простая вещь - есть в любом уважающем себя графическом редакторе. В nip2 это тоже есть, но не так очевидно. Мне пришлось некоторое время поломать голову и проявить немного сообразительности: порог, как выясняется, можно сделать в два этапа. В nip2 есть простые статистические операции: среднее, минимум, максимум и прочее. Выделяем изображение и находим, например, среднее (Toolkits - Math - Statistics - Mean). В следующей ячейке появится число:
Теперь выделяем, зажав Shift, сначала ячейку с числом, а потом ячейку с картинкой. После чего идём в математику (Toolkits - Math) и ищем Relational (Соотношения). Выбираем Less than - это ли не порог? Отлично, в следующей ячейке появится чёрно-белое изображение с порогом. На скриншоте выделено полупрозрачным.
Обновлено: оказывается, всё проще - в nip2 недавно появилась специальная функция порога, которая упрятана в меню Toolkits - Image - Select - Threshold.

\subsubsection{Склеивание изображений в nip2.}
Чтобы склеить несколько изображений в одно, вовсе не нужен фотошоп - с этим прекрасно и быстро справляется nip2. Причём справляется тем лучше, чем больше изображений или фотографий нужно склеить. Например, если у вас имеются снимки со сканирующего микроскопа и нужно склеить десяток снимков - это лучше сделать в nip2. Для этого идём в меню Toolkits - Image - Join - Left to Right если хотим склеить изображения по горизонтали (левый край к правому краю) или Top to Bottom (если нужно склеить верхний край изображения к нижнему краю). Вот что при этом получается:


Пользуясь Toolbox - Image - Join, легко склеить несколько больших изображений в одно для последующего просмотра и анализа.


\subsubsection{Корректировка перекоса яркости (tilt brightness)}
Следует отметить, что при научных съёмках часто на изображениях появляется перекос яркости: когда одна часть изображения освещения сильнее другой (меняющаяся яркость от края изображения к середине). Этот достаточно неприятный эффект можно устранить в nip2 так: Tools - Filters - Tilt brightness.
Это позволит восстановить освещённость на изображении. А используя табличное свойство nip2, вы получаете возможность оперативно перерисовать большое изображение с учётом скорректированной яркости.
